const template = `<p>Vue</p>`;

const State = {
  initial: 1, // 初始状态
  tagOpen: 2, // 标签开始状态
  tagName: 3, // 标签名状态
  text: 4,  // 文本状态
  tagEnd: 5,  // 标签结束状态
  tagEndName: 6,  // 标签结束名状态
};

// 判断一个字符是否是字母
function isAlpha(char) {
  return (char >= "a" && char <= "z") || (char >= "A" && char <= "Z");
}

// 词法分析, 将模板字符串转换为 tokens
function tokenize(str) {
  // 当前状态
  let currentState = State.initial;
  // 用于存储当前正在解析的字符
  const chars = [];
  // 用于存储 tokens
  const tokens = [];
  // 只要模板字符串不为空，就一直解析
  while (str) {
    const char = str[0];
    switch (currentState) {
      // 初始状态
      case State.initial:
        // 如果当前字符是 <，则进入标签开始状态
        if (char === "<") {
          currentState = State.tagOpen;
          // 消费掉当前字符
          str = str.slice(1);
        } else if (isAlpha(char)) {
          // 如果当前字符是字母，则进入文本状态
          currentState = State.text;
          // 存储当前字符
          chars.push(char);
          // 消费掉当前字符
          str = str.slice(1);
        }
        break;
      case State.tagOpen:
        if (isAlpha(char)) {
          currentState = State.tagName;
          chars.push(char);
          str = str.slice(1);
        } else if (char === "/") {
          currentState = State.tagEnd;
          str = str.slice(1);
        }
        break;
      case State.tagName:
        if (isAlpha(char)) {
          chars.push(char);
          str = str.slice(1);
        } else if (char === ">") {
          currentState = State.initial;
          tokens.push({
            type: "tag",
            name: chars.join(""),
          });
          chars.length = 0;
          str = str.slice(1);
        }
        break;
      case State.text:
        if (isAlpha(char)) {
          chars.push(char);
          str = str.slice(1);
        } else if (char === "<") {
          currentState = State.tagOpen;
          tokens.push({
            type: "text",
            content: chars.join(""),
          });
          chars.length = 0;
          str = str.slice(1);
        }
        break;
      case State.tagEnd:
        if (isAlpha(char)) {
          currentState = State.tagEndName;
          chars.push(char);
          str = str.slice(1);
        }
        break;
      case State.tagEndName:
        if (isAlpha(char)) {
          chars.push(char);
          str = str.slice(1);
        } else if (char === ">") {
          currentState = State.initial;
          tokens.push({
            type: "tagEnd",
            name: chars.join(""),
          });
          chars.length = 0;
          str = str.slice(1);
        }
        break;
    }
  }

  return tokens;
}

console.log(tokenize(template));

